-
Notifications
You must be signed in to change notification settings - Fork 4
86b82fa34 - feat: add url fragment linking to tabs on edit sponsor page #751
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
📝 WalkthroughWalkthroughMaps EditSponsorPage tabs to URL hash fragments, initializes and syncs selected tab from window.location.hash, updates the hash on tab changes, exports helpers ( Changes
Sequence Diagram(s)sequenceDiagram
participant Browser
participant EditSponsorPage
participant TabState
Note over Browser,EditSponsorPage: Initial page load
Browser->>EditSponsorPage: load URL (may include `#fragment`)
EditSponsorPage->>EditSponsorPage: getTabFromUrlFragment()
EditSponsorPage->>TabState: set selectedTab
Note over Browser,EditSponsorPage: User selects a tab
Browser->>EditSponsorPage: click tab
EditSponsorPage->>EditSponsorPage: onTabChange -> getFragmentFromValue()
EditSponsorPage->>Browser: set window.location.hash
EditSponsorPage->>TabState: update selectedTab
Note over Browser,EditSponsorPage: External hash change (e.g., back/forward)
Browser->>EditSponsorPage: window.location.hash changes
EditSponsorPage->>EditSponsorPage: hashchange listener -> getTabFromUrlFragment()
EditSponsorPage->>TabState: resync selectedTab
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @src/pages/sponsors/edit-sponsor-page.js:
- Around line 116-118: The useEffect using window.location.hash in the
dependency array won't re-run on hash changes; replace it with a hashchange
event listener: in the effect that currently calls
setSelectedTab(getTabFromUrlFragment()), register
window.addEventListener('hashchange', handler) where handler calls
setSelectedTab(getTabFromUrlFragment()), call the handler once on mount to
initialize, and remove the listener in the cleanup; remove window.location.hash
from the dependency array (use []).
🧹 Nitpick comments (1)
src/pages/sponsors/edit-sponsor-page.js (1)
46-64: Helper functions look good, consider consolidating the tab definition.The mapping and helper functions are well-structured. The fallback to index 0 for unrecognized fragments correctly implements the PR requirement.
Consider deriving
tabsToFragmentMapfrom thetabsarray (or vice versa) to avoid maintaining two separate lists that must stay in sync. For now, this is acceptable.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/pages/sponsors/edit-sponsor-page.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
🔇 Additional comments (2)
src/pages/sponsors/edit-sponsor-page.js (2)
120-123: LGTM!Setting
window.location.hashcorrectly updates the URL and adds a browser history entry, enabling back/forward navigation between tabs.
155-155: Formatting change acknowledged.Minor whitespace adjustment in the sx prop—no functional impact.
smarcet
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@niko-exo please review
| const result = tabsToFragmentMap.indexOf( | ||
| window.location.hash.replace("#", "") | ||
| ); | ||
| return result > -1 ? result : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on the initial load
general tab should be selected hence #general should be show by default
if (result > -1) return result;
if (window.location.hash) window.location.hash = "general";
return 0
```;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! If the general fragment is provided, then it will use it. If not it will retrieve 0, which means use the general fragment. Note that the general fragment is included on the 0 position of the array above the function. I think this function is performing what you mean.
| const [selectedTab, setSelectedTab] = useState(0); | ||
| const [selectedTab, setSelectedTab] = useState(getTabFromUrlFragment()); | ||
|
|
||
| useEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@niko-exo
rite now the tab selection only updates from the URL hash on initial page load. The effect useEffect(..., [window.location.hash]) won’t reliably fire on hash updates because changing window.location.hash doesn’t trigger a React re-render.
To support SPA-style hash navigation (manual hash edits, back/forward), please replace that effect with a hashchange listener
22f0d4b to
9c4adf3
Compare
|
#756 Unblocks this pull request. |
9c4adf3 to
c3e31c6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@src/pages/sponsors/__tests__/edit-sponsor-page.test.js`:
- Around line 144-151: The test's assertion expects window.location.hash without
the leading '#' but JSDOM stores hashes with the '#' prefix; update the
assertion in src/pages/sponsors/__tests__/edit-sponsor-page.test.js to expect
"#forms" instead of "forms" (the component sets the fragment via
getFragmentFromValue() in edit-sponsor-page.js which returns values without '#',
but window.location.hash will include it). Ensure any other assertions in this
test that check window.location.hash are adjusted the same way.
- Line 17: Remove the global.window override that stubs the entire JSDOM window
(the line `global.window = { location: { pathname: "/sponsor-forms/items" } };`)
so tests use the real JSDOM window and its Location API; rely on existing test
setup that uses Object.defineProperty to modify window.location or
window.location.hash when needed, and ensure no other tests expect the stubbed
object.
- Around line 153-217: The test currently only checks existence of tab panels
which is a false positive because CustomTabPanel renders all panels
hidden/visible; update the test to wait for the component to react to the hash
change (use waitFor or findByTestId) and assert visibility instead of mere
existence: after setting location.hash="#general" wait for simple-tabpanel-0 to
be visible (expect(...).toBeVisible()) and that simple-tabpanel-1 is hidden
(expect(...).not.toBeVisible() or expect(...).toHaveAttribute('hidden')); then
after setting hash="#users" wait for simple-tabpanel-1 to be visible and assert
simple-tabpanel-0 is hidden. Use screen.findByTestId or waitFor +
screen.getByTestId and the jest-dom matchers to check visibility; target the
test wrapping EditSponsorPage and the simple-tabpanel-* test ids.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/pages/sponsors/__tests__/edit-sponsor-page.test.jssrc/pages/sponsors/edit-sponsor-page.jssrc/reducers/sponsors/sponsor-reducer.jssrc/reducers/summits/current-summit-reducer.js
🚧 Files skipped from review as they are similar to previous changes (1)
- src/pages/sponsors/edit-sponsor-page.js
🧰 Additional context used
🧬 Code graph analysis (2)
src/reducers/sponsors/sponsor-reducer.js (15)
src/reducers/summits/current-summit-reducer.js (2)
DEFAULT_STATE(217-223)DEFAULT_STATE(217-223)src/reducers/payment_profiles/payment-profile-reducer.js (1)
DEFAULT_STATE(39-42)src/reducers/sponsors/sponsor-customized-form-reducer.js (1)
DEFAULT_STATE(41-43)src/reducers/sponsors/sponsor-page-forms-list-reducer.js (1)
DEFAULT_STATE(29-51)src/reducers/sponsors/sponsor-list-reducer.js (1)
DEFAULT_STATE(25-34)src/reducers/badges/badge-feature-list-reducer.js (1)
DEFAULT_STATE(23-28)src/reducers/sponsors/sponsor-social-network-reducer.js (1)
DEFAULT_STATE(35-38)src/reducers/sponsors/sponsor-material-reducer.js (1)
DEFAULT_STATE(36-39)src/reducers/badges/badge-type-reducer.js (1)
DEFAULT_STATE(42-45)src/reducers/sponsors/sponsor-advertisement-reducer.js (1)
DEFAULT_STATE(39-42)src/reducers/badges/access-level-list-reducer.js (1)
DEFAULT_STATE(23-28)src/reducers/badges/badge-type-list-reducer.js (1)
DEFAULT_STATE(23-28)src/reducers/badges/access-level-reducer.js (1)
DEFAULT_STATE(34-37)src/reducers/badges/badge-feature-reducer.js (1)
DEFAULT_STATE(36-39)src/reducers/refund_policies/refund-policy-list-reducer.js (1)
DEFAULT_STATE(25-30)
src/reducers/summits/current-summit-reducer.js (16)
src/reducers/events/summit-event-reducer.js (1)
DEFAULT_STATE(108-115)src/reducers/tickets/ticket-list-reducer.js (1)
DEFAULT_STATE(28-45)src/reducers/tickets/ticket-reducer.js (1)
DEFAULT_STATE(63-67)src/reducers/attendees/attendee-reducer.js (1)
DEFAULT_STATE(56-59)src/reducers/promocodes/promocode-reducer.js (1)
DEFAULT_STATE(78-83)src/reducers/tickets/ticket-type-reducer.js (1)
DEFAULT_STATE(42-45)src/reducers/events/event-type-reducer.js (1)
DEFAULT_STATE(62-65)src/reducers/locations/location-list-reducer.js (1)
DEFAULT_STATE(24-28)src/reducers/locations/room-reducer.js (1)
DEFAULT_STATE(47-50)src/reducers/events/event-category-list-reducer.js (1)
DEFAULT_STATE(25-27)src/reducers/events/event-category-reducer.js (1)
DEFAULT_STATE(51-55)src/reducers/speakers/speaker-reducer.js (1)
DEFAULT_STATE(52-55)src/reducers/events/event-material-reducer.js (1)
DEFAULT_STATE(42-45)src/reducers/badges/badge-type-reducer.js (1)
DEFAULT_STATE(42-45)src/reducers/locations/floor-reducer.js (1)
DEFAULT_STATE(37-40)src/reducers/locations/location-reducer.js (1)
DEFAULT_STATE(67-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
🔇 Additional comments (2)
src/reducers/sponsors/sponsor-reducer.js (1)
135-139: LGTM — exportingDEFAULT_STATEis consistent and safe.
This aligns with the repo pattern for reducer default state access.src/reducers/summits/current-summit-reducer.js (1)
217-223: LGTM —DEFAULT_STATEexport is a clean consistency update.
No behavioral impact, just improved reuse.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| const usersTabReference = screen.getByText("edit_sponsor.tab.forms"); | ||
|
|
||
| await act(async () => { | ||
| await userEvent.click(usersTabReference); | ||
| }); | ||
|
|
||
| expect(window.location.hash).toBe("forms"); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, find and read the test file
cat -n src/pages/sponsors/__tests__/edit-sponsor-page.test.js | head -200Repository: fntechgit/summit-admin
Length of output: 6883
🏁 Script executed:
# Find and read the EditSponsorPage component
cat -n src/pages/sponsors/edit-sponsor-page.js | head -300Repository: fntechgit/summit-admin
Length of output: 11190
Fix hash format to match JSDOM behavior.
window.location.hash always includes the leading # when accessed in real JSDOM. The component assigns "forms" (line 129 of edit-sponsor-page.js calls getFragmentFromValue() which returns fragment values without #), but the test assertion should expect the actual stored value with the # prefix.
🔧 Suggested fix
- expect(window.location.hash).toBe("forms");
+ expect(window.location.hash).toBe("#forms");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const usersTabReference = screen.getByText("edit_sponsor.tab.forms"); | |
| await act(async () => { | |
| await userEvent.click(usersTabReference); | |
| }); | |
| expect(window.location.hash).toBe("forms"); | |
| }); | |
| const usersTabReference = screen.getByText("edit_sponsor.tab.forms"); | |
| await act(async () => { | |
| await userEvent.click(usersTabReference); | |
| }); | |
| expect(window.location.hash).toBe("#forms"); | |
| }); |
🤖 Prompt for AI Agents
In `@src/pages/sponsors/__tests__/edit-sponsor-page.test.js` around lines 144 -
151, The test's assertion expects window.location.hash without the leading '#'
but JSDOM stores hashes with the '#' prefix; update the assertion in
src/pages/sponsors/__tests__/edit-sponsor-page.test.js to expect "#forms"
instead of "forms" (the component sets the fragment via getFragmentFromValue()
in edit-sponsor-page.js which returns values without '#', but
window.location.hash will include it). Ensure any other assertions in this test
that check window.location.hash are adjusted the same way.
|
Ready for review @smarcet |
* Add test id to make testing more feasible.
c3e31c6 to
f805edb
Compare
|
Rebase branch |
smarcet
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
ref: https://app.clickup.com/t/86b82fa34
86b82fa34 - feat: add url fragment linking to tabs on edit sponsor page
Changelog
Links
86b82fa34 - Add TAB deep-linking using URL fragment
Evidence
2026-01-12_09-56-27.mp4
Summary by CodeRabbit
New Features
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.